package com.one.react.internal;

import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import com.sun.source.util.TreeScanner;
import com.sun.tools.javac.parser.JavacParser;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.Context;

import java.util.List;

import javax.lang.model.element.Name;

public class FieldAccessTranslator extends TreeScanner<Tree, Void> {
    private Context context;
    private List<JCTree.JCVariableDecl> observableVars;
    private TreeMaker F;

    public FieldAccessTranslator(Context context, List<JCTree.JCVariableDecl> observableVars) {
        this.context = context;
        this.F = TreeMaker.instance(context);
        this.observableVars = observableVars;
    }

    @Override
    public Tree visitMethod(MethodTree node, Void unused) {
        JCTree.JCMethodDecl tree = (JCTree.JCMethodDecl) node;
        TreeTranslator translator = new MyTranslator();
        return translator.translate(tree);
    }

    private class MyTranslator extends TreeTranslator {
        @Override
        public void visitExec(JCTree.JCExpressionStatement tree) {
            StateVarAccessModifier modifier = new StateVarAccessModifier();
            JCTree.JCExpressionStatement newStat = modifier.translate(tree);
            /*if (modifier.hasStateVarAccess) {
                String code = modifier.stateVarName + ".addObserver(obj -> " + newStat.expr + ");";
                JCTree.JCExpression expr = MyParser.getInstance(context)
                        .getParserFor(code)
                        .parseExpression();
                newStat = F.Exec(expr);
            }*/
            result = newStat;
        }
    }

    private class StateVarAccessModifier extends TreeTranslator {
        private boolean hasStateVarAccess;
        private Name stateVarName;

        @Override
        public void visitApply(JCTree.JCMethodInvocation tree) {
            if (tree.meth instanceof JCTree.JCFieldAccess) {
                JCTree.JCFieldAccess access = (JCTree.JCFieldAccess) tree.meth;
                if (access.name.contentEquals("update")) {
                    return;
                }
            }
            super.visitApply(tree);
        }

        @Override
        public void visitIdent(JCTree.JCIdent tree) {
            if (isStateVar(tree.name)) {
                stateVarName = tree.name;
                hasStateVarAccess = true;
                String code = tree.name + ".get()";
                result = MyParser.getInstance(context)
                        .getParserFor(code)
                        .parseExpression();
            } else {
                result = tree;
            }
        }
    }

    private boolean isStateVar(Name name) {
        for (JCTree.JCVariableDecl observableVar : observableVars) {
            if (observableVar.name == name) {
                return true;
            }
        }
        return false;
    }
}
